
#include "handy/handy/handy.h"
#include <algorithm>
#include <stdio.h>
#include <string>
#include <stdint.h>
#include <arpa/inet.h>
#include <cerrno>
#include <map>

#include "common.h"
#include "ikcp.h"
#include "xudp.pb.h"

using namespace std;
using namespace handy;

map<int, ikcpcb*> g_mkcp;
UdpServerPtr s;

int xkcp_output(const char *buf, int len, ikcpcb *kcp, void *user) {
	Ip4Addr* ip4 = (Ip4Addr*)user;
	errno = 0;
	s->sendTo(buf, len, *ip4);
	if (errno) {
		fatal("send buff failed");
	}
	return len;
}

ikcpcb* create_kcp(int iconv, Ip4Addr peer) {
	Ip4Addr* ip4 = new Ip4Addr();
	*ip4 = peer;

	ikcpcb* kcp = ikcp_create(1, (void*)ip4);
	kcp->output = xkcp_output;
	ikcp_wndsize(kcp, 1000, 1000);
	ikcp_nodelay(kcp, 1, 10, 2, 1);
	return kcp;
}

void handle_msg(ikcpcb* kcp) {
	char b[1000];
	int ret = 0;
	do {
		ret = ikcp_recv(kcp, b, sizeof(b));
		if ( ret < 0){
			if (ret == -3) {
				fatal("recv error:%d", ret);
			}
		}
		if (ret > 0) {
			xmsg m;
			bool suc = m.ParseFromArray(b, ret);
			if (!suc) {
				fatal("parse failed");
			}	
			info("id:%d,time:%ld",  m.id(), util::timeMilli());
		}
	} while (ret > 0);
	//ikcp_flush(kcp);
}

int main() {
	setloglevel("INFO");
  setlogfile("test_server_kcp");
	EventBase base;
	Signal::signal(SIGINT, [&] { base.exit(); });

	s = handy::UdpServer::startServer(&base, "", SERVER_PORT);
	exitif(s == NULL, "start udp server failed");
	s->onMsg([](const UdpServerPtr& p, Buffer buf, Ip4Addr peer) {
		int iconv = ikcp_getconv(buf.data());
		ikcpcb* kcp = NULL;
		if (g_mkcp.find(iconv) == g_mkcp.end()) {
			 kcp = create_kcp(iconv, peer);
			 g_mkcp[iconv] = kcp;
		} else {
			kcp = g_mkcp[iconv];
		}

		ikcp_input(kcp, buf.data(), buf.size());
		handle_msg(kcp);
	});
	base.runAfter(0, [&]() {
		for (map<int, ikcpcb*>::iterator itr = g_mkcp.begin(); itr != g_mkcp.end();  itr++) {
			ikcp_update(itr->second, (IUINT32)util::timeMilli());
		}
	}, 2);	
	base.loop();
	info("program exited");
}
